	//---------------------------------------------------------------------
	// Includes
	//---------------------------------------------------------------------		
	#include <string>
	#include <assert.h>		
	#include <Settings.hpp>
	#include <Tools/Log.hpp>
	#include <Rendering/OpenGL.hpp>
	#include <Rendering/Renderer.hpp>	
	#include <Geometry/PredefinedShape.hpp>	
		
	//---------------------------------------------------------------------
	// Macros
	//---------------------------------------------------------------------
	// the ARB extension names should disappear once they are finally
	// adopted in GL2.0 - the GL_GLEXT_PROTOTYPES comes from NVidia's
	// glext.h header	
	#define GL_OBJECT_COMPILE_STATUS GL_OBJECT_COMPILE_STATUS_ARB
	#define GL_OBJECT_LINK_STATUS GL_OBJECT_LINK_STATUS_ARB
	#define GL_OBJECT_INFO_LOG_LENGTH GL_OBJECT_INFO_LOG_LENGTH_ARB

	#define GLhandle GLhandleARB
	#define GLchar GLcharARB

	#define glUseProgramObject glUseProgramObjectARB
	//#define glActiveTexture glActiveTextureARB
	#define glCreateShaderObject glCreateShaderObjectARB
	//#define glShaderSource glShaderSourceARB
	//#define glCompileShader glCompileShaderARB
	#define glGetObjectParameteriv glGetObjectParameterivARB
	#define glCreateProgramObject glCreateProgramObjectARB
	#define glAttachObject glAttachObjectARB
	//#define glUniform3fv glUniform3fvARB
	//#define glGetUniformLocation glGetUniformLocationARB
	#define glGetInfoLog glGetInfoLogARB
	#define glDeleteObject glDeleteObjectARB
	//#define glLinkProgram glLinkProgramARB

	#define printOpenGLError() printGLError(__FILE__, __LINE__)	
	#define printInfoLog(Handle) printInfoLogGL(Handle,__FILE__, __LINE__)
	
namespace Rendering {	
	
	//---------------------------------------------------------------------
	// Functions utils
	//---------------------------------------------------------------------	
	static int printGLError(char *file, int line) {
		GLenum  glErr;
		int retCode = 0;
		char *err;
		// returns 1 if an OpenGL error occurred, 0 otherwise.
		glErr = glGetError();
		while (glErr != GL_NO_ERROR) {
			err = (char*)gluErrorString(glErr);
			Tools::Error("file: %s line: %d \n glError: %s",file,line,err);
			retCode = 1;
			glErr = glGetError();
		}
		return retCode;
	}
	//---------------------------------------------------------------------
	static void printInfoLogGL(GLhandle obj, char *file, int line)
	{
		GLint infologLength = 0;
		GLint charsWritten = 0;
		GLchar *infoLog;
		printGLError(file, line);
		glGetObjectParameteriv(obj,GL_OBJECT_INFO_LOG_LENGTH,&infologLength);
		printGLError(file, line);
		if(infologLength > 0) {
			infoLog = (GLchar *)malloc(infologLength);
			if(infoLog == NULL) {
				Tools::Error("Could not allocate InfoLog buffer");
				exit(1);
			}
			glGetInfoLog(obj,infologLength,&charsWritten,infoLog);
			if(charsWritten) Tools::Error("InfoLog:\n%s\n",infoLog);
				free(infoLog);
		}
		printGLError(file, line);
	}
	//---------------------------------------------------------------------
	static bool IsStandardUniform( const std::string& name) {
		std::string standart[] = { "gl_ModelViewProjectionMatrix", 
								   "gl_NormalMatrix", 
								   "gl_ModelViewMatrix",
								   "gl_ModelViewProjectionMatrixTranspose" };
		int size, i;
		size = 4;
		i = 0;
		while (i<size && (standart[i].compare(name)!=0))
			++i;
		return i != size;
	}
	//---------------------------------------------------------------------
	static bool IsTextureType(TEnumeration type) {
		TEnumeration  textureType[] = {  GL_SAMPLER_1D,
									 	 GL_SAMPLER_2D,
										 GL_SAMPLER_3D,
										 GL_SAMPLER_CUBE,
										 GL_SAMPLER_1D_SHADOW,
										 GL_SAMPLER_2D_SHADOW };
										 // TODO Add rectangular texture		  
		int size, i;
		size = 6;
		i = 0;
		while (i<size && (type!=textureType[i]))
			++i;
		return i != size;
	}
	
	//---------------------------------------------------------------------
	bool checkFramebufferStatus() {
		GLenum status;
		status=(GLenum)glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
		switch(status) {
			case GL_FRAMEBUFFER_COMPLETE_EXT:
				return true;
			case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
				Tools::Error("Framebuffer incomplete,incomplete attachment");
				return false;
			case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
				Tools::Error("Unsupported framebuffer format");
				return false;
			case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
				Tools::Error("Framebuffer incomplete,missing attachment");
				return false;
			case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
				Tools::Error("Framebuffer incomplete,attached images must have same dimensions");
				return false;
			case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
				Tools::Error("Framebuffer incomplete,attached images must have same format");
				return false;
			case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
				Tools::Error("Framebuffer incomplete,missing draw buffer");
				return false;
			case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
				Tools::Error("Framebuffer incomplete,missing read buffer");
				return false;
		}
		return false;
	}
	

	//---------------------------------------------------------------------
	// FPS Counter methods	
	//---------------------------------------------------------------------
	float FPSCounter::framerate;
	
	
	//---------------------------------------------------------------------
	// Renderering Surface methods	
	//---------------------------------------------------------------------
	void RenderingSurface::Initialize(int argc, char** argv, const char * title,
				void (*display)(void), void (*reshape)(int width, int height),
				void (*keyboard)(unsigned char key, int x, int y),
				void (*special)(int key, int x, int y),
				void (*mouse)(int button, int state, int x, int y),
				void (*motion)(int, int) ) const {
		// Initialize Glut
		glutInit(&argc, argv);		
		glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
		glutInitWindowSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
		glutCreateWindow(title);
		glutKeyboardFunc(keyboard);
		glutSpecialFunc(special);
		glutDisplayFunc(display);
		glutReshapeFunc(reshape);
		glutMouseFunc(mouse);
		glutPassiveMotionFunc(motion);
		// Initialize renderer
		Renderer::Instance().Initialize();
	}
	//---------------------------------------------------------------------
	void RenderingSurface::SetSize(int width, int height) { 
		surfaceWidth = width;
		surfaceHeight = height;
	}
	//---------------------------------------------------------------------
	void RenderingSurface::WarpMousePosition(int x, int y) { 
		glutWarpPointer(x,y);
	}
	//---------------------------------------------------------------------
	RenderingSurface::RenderingSurface() {
		surfaceWidth = DEFAULT_WIDTH;
		surfaceHeight = DEFAULT_HEIGHT;
	}
	//---------------------------------------------------------------------
	RenderingSurface& RenderingSurface::Instance() {
		// The unique instance
		static RenderingSurface instance;
		return instance;		
	}	
	//---------------------------------------------------------------------
	void RenderingSurface::Finalize() {
		//glutDestroyWindow(0);
	}

	//---------------------------------------------------------------------
	// Renderer methods
	//---------------------------------------------------------------------
	Renderer::Renderer() { 
	}
	//---------------------------------------------------------------------
	Renderer& Renderer::Instance() {
		// The unique instance
		static Renderer instance;
		return instance;		
	}	
	//---------------------------------------------------------------------
	void Renderer::Initialize() const{		
		// Initialise GLEW to check extension
		GLenum error = glewInit();
		if (GLEW_OK != error) {		
			Tools::Error("Glew init failed : %s\n", glewGetErrorString(error));
		}
		else {
			Tools::Info("GLew init success : Using GLEW %s\n", glewGetString(GLEW_VERSION));
		}
		// OpenGL Intialization
		//glEnable(GL_LIGHT0);
		glDisable(GL_LIGHTING);
		//glEnable(GL_BLEND);
		//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);		
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LESS);
		glShadeModel(GL_SMOOTH);
	}
	//---------------------------------------------------------------------
	void Renderer::Run() const{
		// Run Glut main loop
		glutMainLoop();
	}
	//---------------------------------------------------------------------
	void Renderer::StartRender() const{
		// Set color & depth reset value
		glClearColor(0.0, 0.0, 0.0, 0.0);
		glClearDepth(1.0);
		// Reset frame & depth buffer
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
	//---------------------------------------------------------------------
	void Renderer::EndRender() const{
		glutSwapBuffers();
		glutPostRedisplay();
	}
	//---------------------------------------------------------------------	
	void Renderer::SetPointOfView(const Matrix::Matrix4& transformation) const{
		// Load identity matrix
		glLoadIdentity();
		// Set point of view transformation
		glMultMatrixf(transformation);
		//gluLookAt( pov.Position[0], pov.Position[1], pov.Position[2],
		//  		 pov.Position[0] + pov.Direction[0], pov.Position[1] + pov.Direction[1], pov.Position[2] + pov.Direction[2],
		//		     pov.Up[0], pov.Up[1], pov.Up[2] );
	}
	//---------------------------------------------------------------------
	void Renderer::SetPointOfView(IPointOfView* pov) const {
		// Load identity matrix
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glMultMatrixf(pov->GetProjectionMatrix());
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glMultMatrixf(pov->GetViewMatrix());
		
	}
	//---------------------------------------------------------------------
	void Renderer::SetProjection(ProjectionType type, const IPointOfView& pov) const{
		// Get viewport dimension
		int width, height;
		width = RenderingSurface::Instance().surfaceWidth;
		height = RenderingSurface::Instance().surfaceHeight;
		// Set projection
		glViewport(0,0,width,height);
		if(type == PERSPECTIVE) {
			// Set perspective projection			
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			float nearValue, farValue;
			pov.GetRangeOfView(nearValue,farValue);
			gluPerspective( pov.GetFieldOfView(), float(width)/float(height), nearValue, farValue);
			glMatrixMode(GL_MODELVIEW);
		}
		else if(type == ORTHOGONAL) {
			// Set orthogonal projection			
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			glOrtho(0.0, width, 0.0, height, -1.0, 1.0);
			glMatrixMode(GL_MODELVIEW);			
		}
		else
			Tools::Error("Projection type invalid");
		
	}
	//---------------------------------------------------------------------
	void Renderer::Draw() const{
		// Add default Light
		//GLfloat ambientLight[]  = { 0.2f, 0.2f, 0.2f, 1.0f };
		//GLfloat diffuseLight[]  = { 0.8f, 0.8f, 0.8, 1.0f };
		//GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f };
		//GLfloat position[] 	= { 0.f, 10.f, 0.f, 1.0f };
		//glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
		//glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
		//glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
		//glLightfv(GL_LIGHT0, GL_POSITION, position);	
		// Render scene
		Geometry::DrawGrid(100);
		Geometry::DrawReferential(1.0f);
		//glRotatef(-90.f,1,0,0);		
	}			
	//---------------------------------------------------------------------	
	void Renderer::Draw(int x, int y, std::string value) const {		
		int size = (int)value.length();
		glRasterPos2i( x, y );
		for(int i=0;i<size;++i) {
			glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, value[i]);
		}
	}
	//---------------------------------------------------------------------
	void Renderer::SetColor(float* color) const {
		glColor3f(color[0],color[1],color[2]);
	}
	//---------------------------------------------------------------------
	void Renderer::PushMatrix() const {
		glPushMatrix();
	}
	//---------------------------------------------------------------------
	void Renderer::MultMatrix(const float* matrix) const {
		glMultMatrixf(matrix);
	}
	//---------------------------------------------------------------------
	void Renderer::PopMatrix() const {
		glPopMatrix();
	}
	//---------------------------------------------------------------------
	void Renderer::LoadMatrix(float* matrix) const {
		glLoadMatrixf(matrix);
	}	
	//---------------------------------------------------------------------
	void Renderer::StartBlending() const {
		glEnable(GL_BLEND);
	}
	//---------------------------------------------------------------------
	void Renderer::EndBlending() const {
		glDisable(GL_BLEND);		
	}
	//---------------------------------------------------------------------
	TRenderingID Renderer::CreateVertexBuffer(VertexBufferType type, int nElement){
		// Generation of buffer ID
		TRenderingID bufferID;
		glGenBuffers(1, &bufferID);
		// Compute size of buffer
		TSize bufferSize;
		bufferSize = nElement * Enumeration::GetBufferDetail(type).size;
		// Bind buffer to set it currend buffer and allocate memory		
		glBindBuffer(GL_ARRAY_BUFFER, bufferID);
		glBufferData(GL_ARRAY_BUFFER, bufferSize, NULL, GL_STREAM_DRAW);
		// Check OpenGL error
		printOpenGLError();
		return bufferID;
	}
	//---------------------------------------------------------------------
	void Renderer::DeleteVertexBuffer(TRenderingID bufferID){
		glDeleteBuffers(1, &bufferID);
		// Check OpenGL error
		printOpenGLError();
	}
	//---------------------------------------------------------------------
	void Renderer::LoadVertexBuffer(TRenderingID bufferID, VertexBufferType type, int nElement, void *data){		
		// Bind buffer & get pointer of allocated memory
		glBindBuffer(GL_ARRAY_BUFFER, bufferID);
		GLvoid* buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
		// Compute size of buffer
		TSize bufferSize;
		bufferSize = nElement * Enumeration::GetBufferDetail(type).size;
		// Set data & unlock buffer
		memcpy(buffer, data, bufferSize);
		glUnmapBuffer(GL_ARRAY_BUFFER);
		// Check OpenGL error
		printOpenGLError();
	}
	//---------------------------------------------------------------------
	void Renderer::EnableVertexBuffer(TRenderingID bufferID, VertexBufferType type, int nElement, int location) {
		BufferDetail detail = Enumeration::GetBufferDetail(type);
		switch (type) {
			case VERTEX_BUFFER :
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glVertexPointer( detail.components, detail.type, 0, 0 );
				glEnableClientState(GL_VERTEX_ARRAY);
				break;
			case COLOR_BUFFER :
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glColorPointer( detail.components, detail.type, 0, 0 );
				glEnableClientState(GL_COLOR_ARRAY);
				break;
			case NORMAL_BUFFER :
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glNormalPointer( detail.type, 0, 0 );
				glEnableClientState(GL_NORMAL_ARRAY);
				break;				
			case TEXCOORD0_BUFFER :
				glClientActiveTextureARB(GL_TEXTURE0);
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glTexCoordPointer( detail.components, detail.type, 0, 0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				break;
			case TEXCOORD1_BUFFER :		
				glClientActiveTextureARB(GL_TEXTURE1);
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glTexCoordPointer( detail.components, detail.type, 0, 0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				break;
			case TEXCOORD2_BUFFER :				
				glClientActiveTextureARB(GL_TEXTURE2);
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glTexCoordPointer( detail.components, detail.type, 0, 0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				break;				
			case INDEX_BUFFER :
				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferID);	
				break;
			case TANGENT_BUFFER :
				glBindBuffer(GL_ARRAY_BUFFER, bufferID);
				glVertexAttribPointer( location, detail.components, detail.type, GL_TRUE, 0, 0);
				glEnableVertexAttribArray(location);
				break;
			default:
				Tools::Error("Renderer::EnableVertexBuffer unknowed buffer type");
				break;
		}
		// Check OpenGL error
		printOpenGLError();
	}
	//---------------------------------------------------------------------
	void Renderer::DisableVertexBuffer(VertexBufferType type, int location) {
	switch (type) {
			case VERTEX_BUFFER :
				glDisableClientState(GL_VERTEX_ARRAY);
				break;
			case COLOR_BUFFER :
				glDisableClientState(GL_COLOR_ARRAY);
				break;
			case NORMAL_BUFFER :
				glDisableClientState(GL_NORMAL_ARRAY);
				break;
			case TEXCOORD0_BUFFER :
				glClientActiveTextureARB(GL_TEXTURE0);
				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
				break;
			case TEXCOORD1_BUFFER :
				glClientActiveTextureARB(GL_TEXTURE1);
				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
				break;
			case TEXCOORD2_BUFFER :
				glClientActiveTextureARB(GL_TEXTURE2);
				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
				break;
			case INDEX_BUFFER :
				break;
			case TANGENT_BUFFER :
				glDisableVertexAttribArray(location);
				break;
			default:
				Tools::Error("Renderer::DisableVertexBuffer unknowed buffer type");
				break;
		}
		// Check OpenGL error
		printOpenGLError();
	}
	//---------------------------------------------------------------------
	void Renderer::RenderMesh(MeshType meshType, int nElements) {
		glDrawArrays( Enumeration::GetMeshType(meshType), 0, nElements );
	}
	//---------------------------------------------------------------------
	void Renderer::RenderIndexedMesh(MeshType meshType, int nElements) {
		glDrawElements( Enumeration::GetMeshType(meshType),  nElements, Enumeration::GetBufferDetail(INDEX_BUFFER).type, 0);
	}
	//---------------------------------------------------------------------
	TRenderingID Renderer::CreateShader(const std::string& vertexShaderSource, const std::string& fragmentShaderSource) {		
		GLint vertexCompiled, fragmentCompiled, shaderLinked;
		TRenderingID vertexID, fragmentID, programID;				
		// Load vertex & fragment shader
		vertexID = glCreateShaderObject(GL_VERTEX_SHADER);
		fragmentID = glCreateShaderObject(GL_FRAGMENT_SHADER);		
		const char* vertexSource = vertexShaderSource.c_str();
		const char* fragmentSource = fragmentShaderSource.c_str();
		glShaderSource(vertexID, 1, &vertexSource, 0);
		glShaderSource(fragmentID, 1, &fragmentSource, 0);
		// Compile vertex shader
		glCompileShader(vertexID);
		printOpenGLError();
		glGetObjectParameteriv(vertexID, GL_OBJECT_COMPILE_STATUS, &vertexCompiled );
		printInfoLog(vertexID);
		// Compile fragment shader
		glCompileShader(fragmentID);
		printOpenGLError();
		glGetObjectParameteriv(fragmentID, GL_OBJECT_COMPILE_STATUS, &fragmentCompiled );
		printInfoLog(fragmentID);
		// Check compilation status
		if(!vertexCompiled || !fragmentCompiled) return 0;		
		// Link shaders & create program
		programID = glCreateProgramObject();
		glAttachObject(programID, vertexID);
		glAttachObject(programID, fragmentID);
		glLinkProgram(programID);
		printOpenGLError();
		glGetObjectParameteriv(programID, GL_OBJECT_LINK_STATUS, &shaderLinked );
		printInfoLog(programID);
		// Check link status
		if(!shaderLinked) return 0;
		
		return programID;
	}	
	//---------------------------------------------------------------------
	void Renderer::GetShaderLocations(TRenderingID programID, ShaderLocalizator& localizator) {
		// Load program
		glUseProgram(programID);
		//
		int numberOfAttributes, numberOfUniforms;
		glGetObjectParameteriv(programID, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &numberOfAttributes);
		glGetObjectParameteriv(programID, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &numberOfUniforms);
		// Get attributs name & index
		GLsizei maxLength, length;
		GLint size;
		GLenum type;
		GLchar name[MAX_ATTRIBUT_NAME_LENGTH];
		maxLength = MAX_ATTRIBUT_NAME_LENGTH;
		int currentUnit = 0;
		for(int index=0; index<numberOfAttributes; ++index) {
			glGetActiveAttrib(programID, index, maxLength, &length, &size, &type, name);
			if( IsTextureType(type) )
				localizator.AddLocation(name,index,currentUnit++);
			else
				localizator.AddLocation(name,index);
		}		
		// Get uniform name & index
		for(int index=0; index<numberOfUniforms; ++index) {
			// Get variables
			glGetActiveUniform(programID, index, maxLength, &length, &size, &type, name);
			// Filter standart unifrom attributes
			if(!IsStandardUniform(name)) {
				if( IsTextureType(type) )
					localizator.AddLocation(name,index,currentUnit++);
				else
					localizator.AddLocation(name,index);
			}
		}
		// Unload program
		glUseProgram(0);
	}
	//---------------------------------------------------------------------
	void Renderer::LoadShaderVariable(int location, const float value) const { 
		assert(location!=DEFAULT_LOCATION);	
		glUniform1f(location, value);
	}
	//---------------------------------------------------------------------
	void Renderer::LoadShaderVariable(int location, const Vector::Vector3& value) const { 
		assert(location!=DEFAULT_LOCATION);	
		glUniform3f(location, value[0], value[1], value[2]);
	}
	//---------------------------------------------------------------------
	void Renderer::LoadShaderVariable(int location, const Matrix::Matrix4& value) const { 
		assert(location!=DEFAULT_LOCATION);		
		glUniformMatrix4fv( location, 1, GL_FALSE, value);
	}
	//---------------------------------------------------------------------
	void Renderer::LoadShaderVariable(int location, const TITexturePointer& value, int unit) const {
		value->Enable(unit);
		assert((location!=DEFAULT_LOCATION) && (unit != DEFAULT_UNIT));		
		glUniform1i(location, unit);
	}
	//---------------------------------------------------------------------
	TRenderingID Renderer::CreateTexture(PixelFormat format, int nLevels, int width, int height, const void* pixels) {
		// Bind texture
		TRenderingID textureID;
		glGenTextures(1, &textureID);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, textureID); 
		// Create tecture
		switch(format) {
			case PIX_R8G8B8A8 :
			case PIX_R16G16B16A16:
			case PIX_R32G32B32A32:
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);			
				glTexImage2D(GL_TEXTURE_2D, 0, 
							 Enumeration::GetPixelFormatDetails(format).internalFormat, 
							 width, height, 0, 
							 Enumeration::GetPixelFormatDetails(format).format, 
							 Enumeration::GetPixelFormatDetails(format).type,
							 (const GLvoid *)pixels);
				break;
			case PIX_DEPTH16:
			case PIX_DEPTH24:
			case PIX_DEPTH32:
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);				
				glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); //GL_LUMINANCE, GL_INTENSITY, and GL_ALPHA
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);				
				//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
				glTexImage2D(GL_TEXTURE_2D, 0, 
							 Enumeration::GetPixelFormatDetails(format).internalFormat, 
							 width, height, 0, 
							 Enumeration::GetPixelFormatDetails(format).format, 
							 Enumeration::GetPixelFormatDetails(format).type,
							 (const GLvoid *)pixels);
				break;
			//default: 
			//	Tools::Error("Skip");
			//	break;

		}
		glBindTexture(GL_TEXTURE_2D, 0);
		/*
		// Set number of mipmap levels
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nLevels);
    
		// Enable mipmap levels generation
	    if (nLevels > 0)
		    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
                 
        // Generate mipmap levels
		int MipMapWidth  = width;
		int MipMapHeight = height;
		for (int i = 0; i <= nLevels; ++i)  {
			glTexImage2D(GL_TEXTURE_2D, i, Enumeration::GetPixelComponents(format), MipMapWidth, MipMapHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
			if (MipMapWidth > 1)  MipMapWidth  = MipMapWidth>>1;
			if (MipMapHeight > 1) MipMapHeight = MipMapHeight>>1;
		}
		
        // Unbind texture
		glBindTexture(GL_TEXTURE_2D, 0);    
		*/
		return textureID;
	}	
	//---------------------------------------------------------------------
	void Renderer::LoadTexture(TRenderingID textureID, TextureType type, int unit) {
		TEnumeration textureTarger = Enumeration::GetTextureType(type);
		glActiveTextureARB(GL_TEXTURE0 + unit);
		glEnable(textureTarger);
		glBindTexture(textureTarger, textureID);
	}	
	//---------------------------------------------------------------------
	void Renderer::SetTexture(TRenderingID textureID, int width, int height, const unsigned char* data) {
		//glBindTexture(GL_TEXTURE_2D, textureID);
		//glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
		//glBindTexture(GL_TEXTURE_2D, 0);
		Tools::Error("SetTexture");
	}
	//---------------------------------------------------------------------
	void Renderer::DeleteTexture(TRenderingID textureID) {
		glDeleteTextures(1, &textureID);
	}
	//---------------------------------------------------------------------
	TRenderingID Renderer::CreateCubeTexture(PixelFormat format, int nLevels, int width, int height, const unsigned char* pixels[6]) {
		// Bind texture
		TRenderingID textureID;
		glGenTextures(1, &textureID);
		glEnable(GL_TEXTURE_CUBE_MAP);
		glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); 
				
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		
		// Create target for cube map
		GLenum target[6] = { 	GL_TEXTURE_CUBE_MAP_POSITIVE_X,
					GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
					GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
					GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
					GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
					GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };
		
		// Set cube's textures
		for(int i=0;i<6;++i)
			glTexImage2D(target[i], 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *)pixels[i]);

		return textureID;
	}
	//---------------------------------------------------------------------
	TRenderingID Renderer::CreateFrameBuffer(int width, int height) {
		TRenderingID frameBufferID;
		glGenFramebuffersEXT(1, &frameBufferID);		
		return frameBufferID;
	}	
	//---------------------------------------------------------------------
	void Renderer::DeleteFrameBuffer(TRenderingID frameBufferID) {		
		glDeleteFramebuffersEXT(1, &frameBufferID);
	}	
	//---------------------------------------------------------------------
	TRenderingID Renderer::CreateTarget(TRenderingID frameBufferID, int width, int height, TargetType type, PixelFormat format) {		
		// Check pixel format regards to type
		if(type == DEPTH_TARGET)
			assert((format==PIX_DEPTH16)||(format==PIX_DEPTH24)||(format==PIX_DEPTH32));
		else
			assert((format==PIX_R8G8B8A8)||(format==PIX_R16G16B16A16)||(format==PIX_R32G32B32A32));
		// Create texture
		TRenderingID componentID = CreateTexture(format, 0, width, height, 0);		
		// Add target component to frame buffers object
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, Enumeration::GetTargetType(type), GL_TEXTURE_2D, componentID, 0);
		
		// Check Frame buffer status
		//glDrawBuffer (GL_FALSE);
		//glReadBuffer (GL_FALSE);
		
		// verify all is well and restore state
		assert(checkFramebufferStatus());
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		printOpenGLError();

        return componentID;
	}
	//---------------------------------------------------------------------
	void Renderer::EnableFrameBuffer(TRenderingID frameBufferID, int width, int height) {
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID);
		glPushAttrib(GL_VIEWPORT_BIT); 
        glViewport(0, 0, width, height);
	}
	//---------------------------------------------------------------------
	void Renderer::DisableFrameBuffer(TRenderingID frameBufferID) {
		glPopAttrib();
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		printOpenGLError();
	}
	//---------------------------------------------------------------------
	void Renderer::EnableShader(TRenderingID programID) {
		glUseProgram(programID);
	}
	//---------------------------------------------------------------------
	void Renderer::DisableShader(TRenderingID programID){
		glUseProgram(0);
	}
	//---------------------------------------------------------------------
}
